1. Medal Counts over Time
When it comes to winning medals in the Summer Olympics, what do the top 10 most successful countries have in common? The below visualizations aim to investigate this question, highighting the US’s journing in becoming the top Summer Olympic medal-winner of all time.
setwd("C:/Users/pantalaimon/Desktop/DATA VIZ/Assignment 1")
ath = read.csv("athletes_and_events.csv")
gdp = read.csv("gdp_pop.csv")
noc = read.csv("noc_regions.csv")
In conducting this investigation, I chose to focus on the National Olympic Committees (NOCs) associated with each team. To begin, I isolated only summer games and calculated the total number of medals won by each of the top 10 medal-winning NOCs:
## Created medal flag
ath$medalflag <- ifelse((ath$Medal=="Gold") | (ath$Medal=="Silver") | (ath$Medal=="Bronze"), 1, 0)
## Created top ten list
top10medal <- ath %>%
mutate_if(is.numeric, funs(ifelse(is.na(.), 0, .))) %>%
filter(Season=="Summer") %>%
filter(medalflag==1) %>%
group_by(NOC) %>%
summarize(totalmedal = sum(medalflag)) %>%
arrange(desc(totalmedal)) %>%
mutate(rank=row_number()) %>%
filter(rank<11)
## Added country variables
top10medal$Country[top10medal$NOC=="USA"] <- "United States"
top10medal$Country[top10medal$NOC=="URS"] <- "Soviet Union"
top10medal$Country[top10medal$NOC=="SWE"] <- "Sweden"
top10medal$Country[top10medal$NOC=="NED"] <- "Netherlands"
top10medal$Country[top10medal$NOC=="ITA"] <- "Italy"
top10medal$Country[top10medal$NOC=="HUN"] <- "Hungary"
top10medal$Country[top10medal$NOC=="GER"] <- "Germany"
top10medal$Country[top10medal$NOC=="GBR"] <- "United Kingdom"
top10medal$Country[top10medal$NOC=="GER"] <- "Germany"
top10medal$Country[top10medal$NOC=="AUS"] <- "Australia"
top10medal$Country[top10medal$NOC=="FRA"] <- "France"
The table below shows the top 10 medal winners of all time by NOC the country associated with them:
top10medal
Next I created a variable for the total number of summer games each of the top 10 NOCs competed in for comparison, and calculated the average number of medals won per games for each NOC.
## Creating count of total games played by each NOC
games <- ath %>%
mutate_if(is.numeric, funs(ifelse(is.na(.), 0, .))) %>%
filter(Season=="Summer") %>%
group_by(NOC) %>%
summarize(countgames = n_distinct(Year)) %>%
filter(NOC %in% top10medal$NOC)
## Joined rankings together with total number of games variable and created variable for average number of medals earned per game
combo <- left_join(games, top10medal, by = "NOC")
combo$ave <- format(round(combo$totalmedal/combo$countgames, 1), nsmall = 1)
Finally I graphed the total number of medals won by each NOC, highlighting the number of medals won by the US. I also created a second graph showing the average number of medals each NOC has won per game:
bar_1 <- ggplot(combo, aes(reorder(NOC, totalmedal), totalmedal)) +
geom_bar(stat = "identity", width = 0.7, fill = ifelse(combo$NOC=="USA", "turquoise4", "grey")) +
coord_flip() +
theme_tufte() +
geom_text(aes(label=totalmedal), hjust=-0.1, color="gray29", size=3.5) +
labs(x="", y="", title = "Total Medals Earned, by NOC") +
theme(legend.position = "none", axis.ticks = element_blank(), axis.text.x = element_blank(), axis.text.y = element_text(color="gray29", size=10), plot.title = element_text(size=15, face="italic", hjust=-0.1))
bar_1

bar_2 <- ggplot(combo, aes(reorder(NOC, totalmedal), ave)) +
geom_bar(stat = "identity", width = 0.7, fill = ifelse(combo$NOC=="USA", "turquoise4", "grey")) +
coord_flip() +
theme_tufte() +
geom_text(aes(label=ave), hjust=-0.1, color="gray29", size=3.5) +
labs(x="", y="", title = "Average Number of Medals Won per Games") +
theme(legend.position = "none", axis.ticks = element_blank(), axis.text.x = element_blank(), axis.text.y = element_text(color="gray29", size=10), plot.title = element_text(size=15, face="italic", hjust=-0.1))
bar_2

Comparing the two graphs above, we see that while the US has earned the most summer games medals overall, the USSR actually had a higher average of medals earned per games.
What about total medals won over time? Below, I created a line graph showing the total number of medals won by NOC over time, and another graph showing the cumulative number of medals won.
## Creating the dataset for medals earned per year
top10time <- ath %>%
mutate_if(is.numeric, funs(ifelse(is.na(.), 0, .))) %>%
filter(Season=="Summer") %>%
filter(NOC %in% top10medal$NOC) %>%
filter(medalflag==1) %>%
group_by(NOC, Year) %>%
summarize(totalyear = sum(medalflag)) %>%
mutate(cumsum = cumsum(totalyear)) %>%
ungroup()
line_1 <- ggplot(top10time, aes(Year, cumsum)) +
geom_line(aes(group=NOC, color=ifelse(top10time$NOC=="USA", "USA", ""))) +
scale_color_manual(values=c("grey", "turquoise4")) +
geom_text(data = top10time %>% filter(Year==2016),
aes(label = paste0(NOC)),
hjust = -.35,
color = "gray29",
size = 3,
check_overlap = TRUE) +
geom_text(data = top10time %>% filter(Year==1988 & NOC=="URS"),
aes(label = paste0(NOC)),
hjust = -.35,
color = "gray29",
size = 3,
check_overlap = TRUE) +
theme_tufte() +
scale_x_continuous(breaks=seq(1896, 2016, 10)) +
labs(x="", y="Cumulative Medals Won", title = "Cumulative Medals Won from 1896 to 2016") +
theme(legend.position = "none", axis.text.y = element_text(color="gray29", size=10), plot.title = element_text(size=15, face="italic", hjust=-0.1))
line_1

line_2 <- ggplot(top10time, aes(Year, totalyear)) +
geom_line(aes(group=NOC, color=ifelse(top10time$NOC=="USA", "USA", ""))) +
scale_color_manual(values=c("grey", "turquoise4")) +
geom_text(data = top10time %>% filter(Year==2016),
aes(label = paste0(NOC)),
hjust = -.35,
color = "gray29",
size = 3,
check_overlap = TRUE) +
geom_text(data = top10time %>% filter(Year==1988 & NOC=="URS"),
aes(label = paste0(NOC)),
hjust = -.35,
color = "gray29",
size = 3,
check_overlap = TRUE) +
theme_tufte() +
scale_x_continuous(breaks=seq(1896, 2016, 10)) +
labs(x="", y="Number of Medals Won", title = "Total Medals Won by Year") +
theme(legend.position = "none",
axis.text.y = element_text(color="gray29", size=10),
plot.title = element_text(size=15, face="italic", hjust=-0.1))
line_2

I depending on what the editor is interested in showing, I would suggest using the line graph of the cumulative number of medals earned because it clearly portrays both the large difference between the total number of of medals earned (ie the values shown for 2016) and shows how the rapid increase in the number of medals collected by the USSR, despite having participated in fewer games. What happened during this period that gave the USSR the edge?
2. Medal Counts adjusted by Population, GDP
Does population or GDP per capita have any influence on winning summer medals?
## Creating a dataset showing medal counts, pop, and gdp
medalcount <- ath %>%
mutate_if(is.numeric, funs(ifelse(is.na(.), 0, .))) %>%
filter(Season=="Summer") %>%
filter(medalflag==1) %>%
group_by(NOC) %>%
summarize(total = sum(medalflag)) %>%
arrange(desc(total)) %>%
mutate(rank=row_number()) %>%
filter(rank<11)
## For some reason, Singapore was miscoded. I also included Russia in place of USSR
gdp$NOC <- as.character(gdp$Code)
gdp$NOC[gdp$Code == "SIN"] <- "SGP"
gdp$NOC[gdp$Code == "RUS"] <- "URS"
medalgdp <- left_join(medalcount, gdp, by="NOC")
## Created variables showing the ratio of medals won to pop and gdp
medalgdp$totalpop <- medalgdp$total/medalgdp$Population
medalgdp$totalgdp <- medalgdp$total/medalgdp$GDP.per.Capita
The above visualizations show the unadjusted medal rankings of each NOC - here, I calculated the ratio of medals won to both population and GDP per capita for each NOC. Then I created two new rankings for medals won using these ratios.
## Creating rankings for population
finalpop <- medalgdp %>%
mutate_if(is.numeric, funs(ifelse(is.na(.), 0, .))) %>%
group_by(NOC, totalpop) %>%
summarize() %>%
arrange(desc(totalpop))
## For some reason the row number function doesn't work, so I hard coded the rankings
finalpop$rank[finalpop$NOC=="HUN"] <- 1
finalpop$rank[finalpop$NOC=="SWE"] <- 2
finalpop$rank[finalpop$NOC=="AUS"] <- 3
finalpop$rank[finalpop$NOC=="NED"] <- 4
finalpop$rank[finalpop$NOC=="GBR"] <- 5
finalpop$rank[finalpop$NOC=="FRA"] <- 6
finalpop$rank[finalpop$NOC=="ITA"] <- 7
finalpop$rank[finalpop$NOC=="GER"] <- 8
finalpop$rank[finalpop$NOC=="USA"] <- 9
finalpop$rank[finalpop$NOC=="URS"] <- 10
finalpop$ranktype <- "Pop"
## Creating rankings for GDP
finalgdp <- medalgdp %>%
mutate_if(is.numeric, funs(ifelse(is.na(.), 0, .))) %>%
group_by(NOC, totalgdp) %>%
summarize() %>%
arrange(desc(totalgdp))
## For some reason the row number function doesn't work, so I hard coded the rankings
finalgdp$rank[finalgdp$NOC=="URS"] <- 1
finalgdp$rank[finalgdp$NOC=="HUN"] <- 2
finalgdp$rank[finalgdp$NOC=="USA"] <- 3
finalgdp$rank[finalgdp$NOC=="ITA"] <- 4
finalgdp$rank[finalgdp$NOC=="GBR"] <- 5
finalgdp$rank[finalgdp$NOC=="FRA"] <- 6
finalgdp$rank[finalgdp$NOC=="GER"] <- 7
finalgdp$rank[finalgdp$NOC=="AUS"] <- 8
finalgdp$rank[finalgdp$NOC=="SWE"] <- 9
finalgdp$rank[finalgdp$NOC=="NED"] <- 10
finalgdp$ranktype <- "GDP"
## Combining all rankings into one dataset
top10medal$ranktype <- "Total"
top10medal.temp <- within(top10medal, rm(totalmedal, Country))
finalgdp <- within(finalgdp, rm(totalgdp))
finalpop <- within(finalpop, rm(totalpop))
top10medal.temp$NOC <- as.character(top10medal.temp$NOC)
combomedal1 <- bind_rows(top10medal.temp, finalgdp, finalpop)
The graph below shows the new adjusted rankings by NOC, highlighting how the US’s ranking changes when adjusted by GDP and population:
multiples_1 <- ggplot(combomedal1, aes(NOC, rank, group=NOC)) +
geom_bar(aes(fill=NOC, alpha=1), stat = "identity", width = 0.7, position = "dodge") +
scale_fill_manual(values=c("grey", "grey", "grey", "grey", "grey", "grey", "grey", "grey", "grey", "turquoise4")) +
theme_tufte() +
coord_flip() +
labs(x="", y="Rank", title = "Medals Rankings, Adjusted for Population and GDP per capita") +
scale_y_continuous(breaks=seq(0, 10, 2)) +
theme(legend.position = "none",
axis.text.y = element_text(color="gray30", size=8),
axis.text.x = element_text(color="gray30", size=10),
plot.title = element_text(size=15, face="italic"),
panel.background = element_rect(fill = "grey95", color = "white"),
panel.grid.major = element_line(color="white")) +
facet_grid(rows = vars(ranktype), scales = "free")
multiples_1

From the graph we can see that while the US ranks 1st in overall (unadjusted) medal count, it ranks much lower (around 9th out of 10) when adjusted for population. It also ranks slighly lower (around 3rd out of 10) when adjusted for GDP per capita. This could suggest that while a country’s population might not factor into a country’s summer medal winnings, GDP per capita might.
3. Host Country Advantage
These next visualizations attempt to investigate whether the top 10 summer Olympics medal winners of all time showed any host country advantage.
## This is the code I copied from the Assignment Instructions which brings in the host country dataset. I added a space after the "," to make matching the countries easier (see below)
wiki_hosts <- read_html("https://en.wikipedia.org/wiki/Summer_Olympic_Games")
hosts <- html_table(html_nodes(wiki_hosts, "table")[[8]], fill=TRUE)
hosts <- hosts[-1,1:3]
hosts$city <- str_split_fixed(hosts$Host, n=2, ", ")[,1]
hosts$country <- str_split_fixed(hosts$Host, n=2, ", ")[,2]
## Creating a new dataset like the ones above
host <- ath %>%
mutate_if(is.numeric, funs(ifelse(is.na(.), 0, .))) %>%
filter(Season=="Summer") %>%
group_by(NOC) %>%
mutate(totalmedal = sum(medalflag)) %>%
ungroup() %>%
filter(NOC %in% top10medal$NOC) %>%
arrange(desc(totalmedal))
## Joining the above dataset with the host country dataset by year
hosts$Year <- as.integer(hosts$Year)
combohosts <- left_join(host, hosts, by = "Year")
At this point I also learned that there was actually no official 1906 Summer Olympics (despite the inclusion of a 1906 Olympics in Athens in the dataset). However I decided to include the 1906 data since I had also included it in the graphs above.
## Here I'm just creating a variable that renames each country that has hosted a summer olympics with that country's NOC. I did this to make it easier to match teams with the hosting country.
combohosts$country[combohosts$City=="Athina"] <- "Greece"
combohosts$hostNOC[combohosts$country=="United States"] <- "USA"
combohosts$hostNOC[combohosts$country=="Soviet Union"] <- "URS"
combohosts$hostNOC[combohosts$country=="Sweden"] <- "SWE"
combohosts$hostNOC[combohosts$country=="Netherlands"] <- "NED"
combohosts$hostNOC[combohosts$country=="Italy"] <- "ITA"
combohosts$hostNOC[combohosts$country=="Hungary"] <- "HUN"
combohosts$hostNOC[combohosts$country=="Germany"] <- "GER"
combohosts$hostNOC[combohosts$country=="United Kingdom"] <- "GBR"
combohosts$hostNOC[combohosts$country=="Germany"] <- "GER"
combohosts$hostNOC[combohosts$country=="West Germany"] <- "GER"
combohosts$hostNOC[combohosts$country=="Australia"] <- "AUS"
combohosts$hostNOC[combohosts$country=="Belgium"] <- "BEL"
combohosts$hostNOC[combohosts$country=="Brazil"] <- "BRA"
combohosts$hostNOC[combohosts$country=="Canada"] <- "CAN"
combohosts$hostNOC[combohosts$country=="China"] <- "CHN"
combohosts$hostNOC[combohosts$country=="Finland"] <- "FIN"
combohosts$hostNOC[combohosts$country=="France"] <- "FRA"
combohosts$hostNOC[combohosts$country=="Greece"] <- "GRE"
combohosts$hostNOC[combohosts$country=="Spain"] <- "ESP"
combohosts$hostNOC[combohosts$country=="Japan"] <- "JPN"
combohosts$hostNOC[combohosts$country=="Mexico"] <- "MEX"
combohosts$hostNOC[combohosts$country=="South Korea"] <- "KOR"
Looking at a table of the final dataset shows that among the top 10 medal-earning NOCs, all but Hungry have participated in summer games they have hosted.
## Creating a flag for each athelete for whether they were playing in their team's country.
combohosts$host_flag <- ifelse(combohosts$NOC==combohosts$hostNOC, 1, 0)
## Creating the final dataset with the average number of medals earned per summer game for hosted games and not-hosted games
host_total <- combohosts %>%
group_by(NOC, host_flag) %>%
mutate(countgames = n_distinct(Year)) %>%
ungroup() %>%
group_by(NOC, host_flag) %>%
mutate(hosttotal = sum(medalflag)) %>%
ungroup() %>%
mutate(medalave = hosttotal/countgames) %>%
group_by(NOC, host_flag, countgames, totalmedal, hosttotal, medalave) %>%
summarise() %>%
arrange(NOC, host_flag) %>%
ungroup()
host_total$host_flag <- ifelse(host_total$host_flag==1, "Hosted", "Not Hosted")
host_total
Finally, I created a slopgraph showing the average number of medals won per games for each NOC for when they were not hosting, and when they were hosting:
slopegraph_1 <- ggplot(host_total, aes(host_flag, medalave, group=NOC)) +
geom_line(aes(color = ifelse(host_total$NOC=="USA", "USA", ""), alpha=1), size = 1.5) +
geom_point(aes(color = ifelse(host_total$NOC=="USA", "USA", ""), alpha=1), size = 3) +
geom_text(data = host_total %>% filter(host_flag=="Hosted"),
aes(label = paste0(NOC)),
hjust = -.35,
color = "gray29",
size = 3,
check_overlap = TRUE) +
scale_color_manual(values=c("grey", "turquoise4")) +
scale_y_continuous(breaks=seq(0, 550, 100)) +
scale_x_discrete(limits=c("Not Hosted", "Hosted")) +
theme_tufte() +
labs(x="", y="", title = "Average Number of Medals Won, per Olympic Games") +
theme(legend.position = "none",
axis.text.y = element_text(color="gray29", size=12),
axis.text.x = element_text(color="gray29", size=12),
plot.title = element_text(size=17, face="italic", hjust=.2, vjust = 1),
panel.grid.major.x = element_line(color = "lightgrey"),
axis.ticks = element_blank())
slopegraph_1

Looking at the slopegraph, it would appear that on average, NOCs earn more medals per Olympic games when they are hosting than when they are not hosting. If a particular country wants to increase their medal count, they might want to consider hosting the summer games!
4. Most successful athletes
The next set of visualizations look at the most “successful” athletes among the top 10 medal-winning NOCs for the Summer Olympics. In particular, we’re interested in seeing which athletes and sport earn the most medals.
## Creating new dataset listing 10 most succesful athletes of all time
top10sucess <- ath %>%
mutate_if(is.numeric, funs(ifelse(is.na(.), 0, .))) %>%
filter(Season=="Summer") %>%
group_by(ID) %>%
mutate(totalmedal = sum(medalflag)) %>%
ungroup() %>%
filter(NOC %in% top10medal$NOC) %>%
arrange(desc(totalmedal)) %>%
group_by(ID, Name, Sex, totalmedal, NOC, Sport) %>%
summarize() %>%
ungroup %>%
arrange(desc(totalmedal)) %>%
mutate(rank=row_number()) %>%
filter(rank<11) %>%
ungroup()
top10sucess$Sex <- ifelse(top10sucess$Sex=="F", "Female", "Male")
First, the below graph shows the top 10 biggest medal-winners of all time for the Summer games only:
## Creating a dotplot seperated by NOC
dotplot_1 <- ggplot(top10sucess, aes(totalmedal, reorder(Name, totalmedal), group=NOC)) +
geom_point(aes(color=NOC, alpha=1), size=5) +
scale_color_manual(values=c("grey", "grey", "grey", "turquoise4")) +
theme_tufte() +
labs(x="Total Medals Won", y="", title = "Top 10 Biggest Medal Winners (Summer Games Only)") +
theme(legend.position = "none",
axis.text.y = element_text(color="gray30", size=10),
axis.text.x = element_text(color="gray30", size=10),
plot.title = element_text(size=15, face="italic", hjust=1.5),
panel.background = element_rect(fill = "grey95", color = "white"),
panel.grid.major = element_line(color="white")) +
facet_grid(rows = vars(NOC), scales = "free", space = "free")
dotplot_1

From the dotplot above, we can see that most of the top 10 highest achieving athletes are on the US team. Additionally,Michael Phelps has the most total medals of all time.
Next, I looked at the distribution of medals won across sport and gender:
## Plotting Medals Won by Sport and Gender
bar_3 <- ggplot(top10sucess, aes(reorder(Sex, totalmedal), totalmedal, group=Sex)) +
geom_bar(stat = "identity", width = 0.7, fill="turquoise4") +
theme_tufte() +
labs(x="Gender", y="Total Medals Won", title = "Medals Won by Sport and Gender") +
theme(legend.position = "none",
axis.text.y = element_text(color="gray30", size=10),
axis.text.x = element_text(color="gray30", size=10),
plot.title = element_text(size=15, face="italic"),
panel.background = element_rect(fill = "grey95", color = "white"),
panel.grid.major = element_line(color="white")) +
facet_grid(cols = vars(Sport), scales = "free", space = "free")
bar_3

From the graph, it would appear that out of the top 10 biggest medal-winning NOCs during the Summer Games, male swimmers were the most sucessful medal-winners (ie, won the most medals overall). Does this mean that countries who want to win more Summer Olympic medals should train more swimmers?
5. Make two plots interactive
I chose to make the above line and slope graphs interactive because I felt readers might be interested in hovering over certain points to obtain their actual values. Although the static version of each graph does give an overall impression of the data, some readers may be more interested in learning the particulars of a certain year or country. Additionally, the ability to zoom in on an image may make the line graph easier to interpret (particularly at the low-end of the x axis where many of the lines overlap)
gline <- ggplotly(line_1)
gline
gslope <- ggplotly(slopegraph_1)
gslope
6. Data Table
The data table below contains data for only Summer Games, and shows the number of medals won by sport for each NOC and year. I chose these variables because I felt readers might be interested to browse the number of medals won by sport for ALL NOCs, not just medals won by the top 10 medal-winners above.
## Preparing a dateframe for the table that includes most variables used in the above visualizations
newdata <- ath %>%
mutate_if(is.numeric, funs(ifelse(is.na(.), 0, .))) %>%
filter(Season=="Summer") %>%
filter(medalflag==1) %>%
group_by(NOC, Year, Sport) %>%
summarize(Medals = sum(medalflag))
newdata %>%
datatable(
rownames = FALSE,
filter = list(position = "top"),
options = list(language = list(sSearch = "Filter:")))
LS0tDQp0aXRsZTogIkhvbWV3b3JrIDEgLSBTdW1tZXIgT2x5bXBpY3MiDQphdXRob3I6ICJKdWxpYSBCbG9vbSINCmRhdGU6ICJGZWJydWFyeSAxNywgMjAxOSINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQpgYGB7ciBTZXR1cCwgaW5jbHVkZT1GQUxTRSwgcmVzdWx0cz0naGlkZScsIHdhcm5pbmc9RkFMU0V9DQogICAgbGlicmFyeShrbml0cikNCiAgICBsaWJyYXJ5KHlhbWwpDQogICAgbGlicmFyeSh0aWR5dmVyc2UpDQogICAgbGlicmFyeShnZ3Bsb3QyKQ0KICAgIGxpYnJhcnkobWFncml0dHIpDQogICAgbGlicmFyeShkcGx5cikNCiAgICBsaWJyYXJ5KG1hZ3JpdHRyKQ0KICAgIGxpYnJhcnkoZ2d0aGVtZXMpDQogICAgbGlicmFyeShydmVzdCkNCiAgICBsaWJyYXJ5KHN0cmluZ3IpDQogICAgbGlicmFyeShwbG90bHkpDQogICAgbGlicmFyeShEVCkNCiAgICBvcHRzX2NodW5rJHNldChmaWcucGF0aD0iaW1hZ2VzLyIsDQogICAgICAgICAgICAgICAgICAgY2FjaGUucGF0aD0iY2FjaGUvIiwNCiAgICAgICAgICAgICAgICAgICBjYWNoZT1GQUxTRSwNCiAgICAgICAgICAgICAgICAgICBlY2hvPVRSVUUsDQogICAgICAgICAgICAgICAgICAgbWVzc2FnZT1GQUxTRSwNCiAgICAgICAgICAgICAgICAgICB3YXJuaW5nPUZBTFNFKSAgDQpgYGANCg0KDQojIyMjIDEuIE1lZGFsIENvdW50cyBvdmVyIFRpbWUNCg0KDQpXaGVuIGl0IGNvbWVzIHRvIHdpbm5pbmcgbWVkYWxzIGluIHRoZSBTdW1tZXIgT2x5bXBpY3MsIHdoYXQgZG8gdGhlIHRvcCAxMCBtb3N0IHN1Y2Nlc3NmdWwgY291bnRyaWVzIGhhdmUgaW4gY29tbW9uPyBUaGUgYmVsb3cgdmlzdWFsaXphdGlvbnMgYWltIHRvIGludmVzdGlnYXRlIHRoaXMgcXVlc3Rpb24sIGhpZ2hpZ2h0aW5nIHRoZSBVUydzIGpvdXJuaW5nIGluIGJlY29taW5nIHRoZSB0b3AgU3VtbWVyIE9seW1waWMgbWVkYWwtd2lubmVyIG9mIGFsbCB0aW1lLg0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCnNldHdkKCJDOi9Vc2Vycy9wYW50YWxhaW1vbi9EZXNrdG9wL0RBVEEgVklaL0Fzc2lnbm1lbnQgMSIpDQphdGggPSByZWFkLmNzdigiYXRobGV0ZXNfYW5kX2V2ZW50cy5jc3YiKQ0KZ2RwID0gcmVhZC5jc3YoImdkcF9wb3AuY3N2IikNCm5vYyA9IHJlYWQuY3N2KCJub2NfcmVnaW9ucy5jc3YiKQ0KYGBgDQoNCkluIGNvbmR1Y3RpbmcgdGhpcyBpbnZlc3RpZ2F0aW9uLCBJIGNob3NlIHRvIGZvY3VzIG9uIHRoZSBOYXRpb25hbCBPbHltcGljIENvbW1pdHRlZXMgKE5PQ3MpIGFzc29jaWF0ZWQgd2l0aCBlYWNoIHRlYW0uIFRvIGJlZ2luLCBJIGlzb2xhdGVkIG9ubHkgc3VtbWVyIGdhbWVzIGFuZCBjYWxjdWxhdGVkIHRoZSB0b3RhbCBudW1iZXIgb2YgbWVkYWxzIHdvbiBieSBlYWNoIG9mIHRoZSB0b3AgMTAgbWVkYWwtd2lubmluZyBOT0NzOg0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCiMjIENyZWF0ZWQgbWVkYWwgZmxhZw0KDQphdGgkbWVkYWxmbGFnIDwtIGlmZWxzZSgoYXRoJE1lZGFsPT0iR29sZCIpIHwgKGF0aCRNZWRhbD09IlNpbHZlciIpIHwgKGF0aCRNZWRhbD09IkJyb256ZSIpLCAxLCAwKQ0KDQojIyBDcmVhdGVkIHRvcCB0ZW4gbGlzdA0KDQp0b3AxMG1lZGFsIDwtIGF0aCAlPiUNCiAgbXV0YXRlX2lmKGlzLm51bWVyaWMsIGZ1bnMoaWZlbHNlKGlzLm5hKC4pLCAwLCAuKSkpICU+JQ0KICBmaWx0ZXIoU2Vhc29uPT0iU3VtbWVyIikgJT4lDQogIGZpbHRlcihtZWRhbGZsYWc9PTEpICU+JQ0KICBncm91cF9ieShOT0MpICU+JQ0KICBzdW1tYXJpemUodG90YWxtZWRhbCA9IHN1bShtZWRhbGZsYWcpKSAlPiUNCiAgYXJyYW5nZShkZXNjKHRvdGFsbWVkYWwpKSAlPiUNCiAgbXV0YXRlKHJhbms9cm93X251bWJlcigpKSAlPiUNCiAgZmlsdGVyKHJhbms8MTEpDQoNCiMjIEFkZGVkIGNvdW50cnkgdmFyaWFibGVzDQoNCnRvcDEwbWVkYWwkQ291bnRyeVt0b3AxMG1lZGFsJE5PQz09IlVTQSJdIDwtICJVbml0ZWQgU3RhdGVzIg0KdG9wMTBtZWRhbCRDb3VudHJ5W3RvcDEwbWVkYWwkTk9DPT0iVVJTIl0gPC0gIlNvdmlldCBVbmlvbiINCnRvcDEwbWVkYWwkQ291bnRyeVt0b3AxMG1lZGFsJE5PQz09IlNXRSJdIDwtICJTd2VkZW4iDQp0b3AxMG1lZGFsJENvdW50cnlbdG9wMTBtZWRhbCROT0M9PSJORUQiXSA8LSAiTmV0aGVybGFuZHMiDQp0b3AxMG1lZGFsJENvdW50cnlbdG9wMTBtZWRhbCROT0M9PSJJVEEiXSA8LSAiSXRhbHkiDQp0b3AxMG1lZGFsJENvdW50cnlbdG9wMTBtZWRhbCROT0M9PSJIVU4iXSA8LSAiSHVuZ2FyeSINCnRvcDEwbWVkYWwkQ291bnRyeVt0b3AxMG1lZGFsJE5PQz09IkdFUiJdIDwtICJHZXJtYW55Ig0KdG9wMTBtZWRhbCRDb3VudHJ5W3RvcDEwbWVkYWwkTk9DPT0iR0JSIl0gPC0gIlVuaXRlZCBLaW5nZG9tIg0KdG9wMTBtZWRhbCRDb3VudHJ5W3RvcDEwbWVkYWwkTk9DPT0iR0VSIl0gPC0gIkdlcm1hbnkiDQp0b3AxMG1lZGFsJENvdW50cnlbdG9wMTBtZWRhbCROT0M9PSJBVVMiXSA8LSAiQXVzdHJhbGlhIg0KdG9wMTBtZWRhbCRDb3VudHJ5W3RvcDEwbWVkYWwkTk9DPT0iRlJBIl0gPC0gIkZyYW5jZSINCmBgYA0KICANClRoZSB0YWJsZSBiZWxvdyBzaG93cyB0aGUgdG9wIDEwIG1lZGFsIHdpbm5lcnMgb2YgYWxsIHRpbWUgYnkgTk9DIHRoZSBjb3VudHJ5IGFzc29jaWF0ZWQgd2l0aCB0aGVtOg0KDQpgYGB7cn0NCnRvcDEwbWVkYWwNCmBgYA0KDQpOZXh0IEkgY3JlYXRlZCBhIHZhcmlhYmxlIGZvciB0aGUgdG90YWwgbnVtYmVyIG9mIHN1bW1lciBnYW1lcyBlYWNoIG9mIHRoZSB0b3AgMTAgTk9DcyBjb21wZXRlZCBpbiBmb3IgY29tcGFyaXNvbiwgYW5kIGNhbGN1bGF0ZWQgdGhlIGF2ZXJhZ2UgbnVtYmVyIG9mIG1lZGFscyB3b24gcGVyIGdhbWVzIGZvciBlYWNoIE5PQy4NCg0KYGBge3J9DQojIyBDcmVhdGluZyBjb3VudCBvZiB0b3RhbCBnYW1lcyBwbGF5ZWQgYnkgZWFjaCBOT0MNCg0KZ2FtZXMgPC0gYXRoICU+JQ0KICBtdXRhdGVfaWYoaXMubnVtZXJpYywgZnVucyhpZmVsc2UoaXMubmEoLiksIDAsIC4pKSkgJT4lDQogIGZpbHRlcihTZWFzb249PSJTdW1tZXIiKSAlPiUNCiAgZ3JvdXBfYnkoTk9DKSAlPiUNCiAgc3VtbWFyaXplKGNvdW50Z2FtZXMgPSBuX2Rpc3RpbmN0KFllYXIpKSAlPiUNCiAgZmlsdGVyKE5PQyAlaW4lIHRvcDEwbWVkYWwkTk9DKQ0KDQojIyBKb2luZWQgcmFua2luZ3MgdG9nZXRoZXIgd2l0aCB0b3RhbCBudW1iZXIgb2YgZ2FtZXMgdmFyaWFibGUgYW5kIGNyZWF0ZWQgdmFyaWFibGUgZm9yIGF2ZXJhZ2UgbnVtYmVyIG9mIG1lZGFscyBlYXJuZWQgcGVyIGdhbWUNCg0KY29tYm8gPC0gbGVmdF9qb2luKGdhbWVzLCB0b3AxMG1lZGFsLCBieSA9ICJOT0MiKQ0KY29tYm8kYXZlIDwtIGZvcm1hdChyb3VuZChjb21ibyR0b3RhbG1lZGFsL2NvbWJvJGNvdW50Z2FtZXMsIDEpLCBuc21hbGwgPSAxKQ0KYGBgDQoNCkZpbmFsbHkgSSBncmFwaGVkIHRoZSB0b3RhbCBudW1iZXIgb2YgbWVkYWxzIHdvbiBieSBlYWNoIE5PQywgaGlnaGxpZ2h0aW5nIHRoZSBudW1iZXIgb2YgbWVkYWxzIHdvbiBieSB0aGUgVVMuIEkgYWxzbyBjcmVhdGVkIGEgc2Vjb25kIGdyYXBoIHNob3dpbmcgdGhlIGF2ZXJhZ2UgbnVtYmVyIG9mIG1lZGFscyBlYWNoIE5PQyBoYXMgd29uIHBlciBnYW1lOg0KDQpgYGB7cn0NCmJhcl8xIDwtIGdncGxvdChjb21ibywgYWVzKHJlb3JkZXIoTk9DLCB0b3RhbG1lZGFsKSwgdG90YWxtZWRhbCkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMC43LCBmaWxsID0gaWZlbHNlKGNvbWJvJE5PQz09IlVTQSIsICJ0dXJxdW9pc2U0IiwgImdyZXkiKSkgKw0KICBjb29yZF9mbGlwKCkgKw0KICB0aGVtZV90dWZ0ZSgpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbD10b3RhbG1lZGFsKSwgaGp1c3Q9LTAuMSwgY29sb3I9ImdyYXkyOSIsIHNpemU9My41KSArDQogIGxhYnMoeD0iIiwgeT0iIiwgdGl0bGUgPSAiVG90YWwgTWVkYWxzIEVhcm5lZCwgYnkgTk9DIikgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChjb2xvcj0iZ3JheTI5Iiwgc2l6ZT0xMCksIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xNSwgZmFjZT0iaXRhbGljIiwgaGp1c3Q9LTAuMSkpDQoNCmJhcl8xDQoNCmJhcl8yIDwtIGdncGxvdChjb21ibywgYWVzKHJlb3JkZXIoTk9DLCB0b3RhbG1lZGFsKSwgYXZlKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5Iiwgd2lkdGggPSAwLjcsIGZpbGwgPSBpZmVsc2UoY29tYm8kTk9DPT0iVVNBIiwgInR1cnF1b2lzZTQiLCAiZ3JleSIpKSArDQogIGNvb3JkX2ZsaXAoKSArDQogIHRoZW1lX3R1ZnRlKCkgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsPWF2ZSksIGhqdXN0PS0wLjEsIGNvbG9yPSJncmF5MjkiLCBzaXplPTMuNSkgKw0KICBsYWJzKHg9IiIsIHk9IiIsIHRpdGxlID0gIkF2ZXJhZ2UgTnVtYmVyIG9mIE1lZGFscyBXb24gcGVyIEdhbWVzIikgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChjb2xvcj0iZ3JheTI5Iiwgc2l6ZT0xMCksIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xNSwgZmFjZT0iaXRhbGljIiwgaGp1c3Q9LTAuMSkpDQoNCmJhcl8yDQpgYGANCg0KQ29tcGFyaW5nIHRoZSB0d28gZ3JhcGhzIGFib3ZlLCB3ZSBzZWUgdGhhdCB3aGlsZSB0aGUgVVMgaGFzIGVhcm5lZCB0aGUgbW9zdCBzdW1tZXIgZ2FtZXMgbWVkYWxzIG92ZXJhbGwsIHRoZSBVU1NSIGFjdHVhbGx5IGhhZCBhIGhpZ2hlciBhdmVyYWdlIG9mIG1lZGFscyBlYXJuZWQgcGVyIGdhbWVzLg0KDQpXaGF0IGFib3V0IHRvdGFsIG1lZGFscyB3b24gb3ZlciB0aW1lPyBCZWxvdywgSSBjcmVhdGVkIGEgbGluZSBncmFwaCBzaG93aW5nIHRoZSB0b3RhbCBudW1iZXIgb2YgbWVkYWxzIHdvbiBieSBOT0Mgb3ZlciB0aW1lLCBhbmQgYW5vdGhlciBncmFwaCBzaG93aW5nIHRoZSBjdW11bGF0aXZlIG51bWJlciBvZiBtZWRhbHMgd29uLg0KDQpgYGB7cn0NCiMjIENyZWF0aW5nIHRoZSBkYXRhc2V0IGZvciBtZWRhbHMgZWFybmVkIHBlciB5ZWFyDQoNCnRvcDEwdGltZSA8LSBhdGggJT4lDQogIG11dGF0ZV9pZihpcy5udW1lcmljLCBmdW5zKGlmZWxzZShpcy5uYSguKSwgMCwgLikpKSAlPiUNCiAgZmlsdGVyKFNlYXNvbj09IlN1bW1lciIpICU+JQ0KICBmaWx0ZXIoTk9DICVpbiUgdG9wMTBtZWRhbCROT0MpICU+JQ0KICBmaWx0ZXIobWVkYWxmbGFnPT0xKSAlPiUNCiAgZ3JvdXBfYnkoTk9DLCBZZWFyKSAlPiUNCiAgc3VtbWFyaXplKHRvdGFseWVhciA9IHN1bShtZWRhbGZsYWcpKSAlPiUNCiAgbXV0YXRlKGN1bXN1bSA9IGN1bXN1bSh0b3RhbHllYXIpKSAlPiUNCiAgdW5ncm91cCgpDQpgYGANCg0KYGBge3J9DQpsaW5lXzEgPC0gZ2dwbG90KHRvcDEwdGltZSwgYWVzKFllYXIsIGN1bXN1bSkpICsNCiAgZ2VvbV9saW5lKGFlcyhncm91cD1OT0MsIGNvbG9yPWlmZWxzZSh0b3AxMHRpbWUkTk9DPT0iVVNBIiwgIlVTQSIsICIiKSkpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCJncmV5IiwgInR1cnF1b2lzZTQiKSkgKw0KICBnZW9tX3RleHQoZGF0YSA9IHRvcDEwdGltZSAlPiUgZmlsdGVyKFllYXI9PTIwMTYpLCANCiAgICAgICAgICAgIGFlcyhsYWJlbCA9IHBhc3RlMChOT0MpKSwgDQogICAgICAgICAgICBoanVzdCA9IC0uMzUsDQogICAgICAgICAgICBjb2xvciA9ICJncmF5MjkiLA0KICAgICAgICAgICAgc2l6ZSA9IDMsDQogICAgICAgICAgICBjaGVja19vdmVybGFwID0gVFJVRSkgKw0KICBnZW9tX3RleHQoZGF0YSA9IHRvcDEwdGltZSAlPiUgZmlsdGVyKFllYXI9PTE5ODggJiBOT0M9PSJVUlMiKSwgDQogICAgICAgICAgICBhZXMobGFiZWwgPSBwYXN0ZTAoTk9DKSksIA0KICAgICAgICAgICAgaGp1c3QgPSAtLjM1LA0KICAgICAgICAgICAgY29sb3IgPSAiZ3JheTI5IiwNCiAgICAgICAgICAgIHNpemUgPSAzLA0KICAgICAgICAgICAgY2hlY2tfb3ZlcmxhcCA9IFRSVUUpICsNCiAgdGhlbWVfdHVmdGUoKSArDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3M9c2VxKDE4OTYsIDIwMTYsIDEwKSkgKw0KICBsYWJzKHg9IiIsIHk9IkN1bXVsYXRpdmUgTWVkYWxzIFdvbiIsIHRpdGxlID0gIkN1bXVsYXRpdmUgTWVkYWxzIFdvbiBmcm9tIDE4OTYgdG8gMjAxNiIpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChjb2xvcj0iZ3JheTI5Iiwgc2l6ZT0xMCksIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xNSwgZmFjZT0iaXRhbGljIiwgaGp1c3Q9LTAuMSkpDQoNCmxpbmVfMQ0KDQpsaW5lXzIgPC0gZ2dwbG90KHRvcDEwdGltZSwgYWVzKFllYXIsIHRvdGFseWVhcikpICsNCiAgZ2VvbV9saW5lKGFlcyhncm91cD1OT0MsIGNvbG9yPWlmZWxzZSh0b3AxMHRpbWUkTk9DPT0iVVNBIiwgIlVTQSIsICIiKSkpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCJncmV5IiwgInR1cnF1b2lzZTQiKSkgKw0KICBnZW9tX3RleHQoZGF0YSA9IHRvcDEwdGltZSAlPiUgZmlsdGVyKFllYXI9PTIwMTYpLCANCiAgICAgICAgICAgIGFlcyhsYWJlbCA9IHBhc3RlMChOT0MpKSwgDQogICAgICAgICAgICBoanVzdCA9IC0uMzUsDQogICAgICAgICAgICBjb2xvciA9ICJncmF5MjkiLA0KICAgICAgICAgICAgc2l6ZSA9IDMsDQogICAgICAgICAgICBjaGVja19vdmVybGFwID0gVFJVRSkgKw0KICBnZW9tX3RleHQoZGF0YSA9IHRvcDEwdGltZSAlPiUgZmlsdGVyKFllYXI9PTE5ODggJiBOT0M9PSJVUlMiKSwgDQogICAgICAgICAgICBhZXMobGFiZWwgPSBwYXN0ZTAoTk9DKSksIA0KICAgICAgICAgICAgaGp1c3QgPSAtLjM1LA0KICAgICAgICAgICAgY29sb3IgPSAiZ3JheTI5IiwNCiAgICAgICAgICAgIHNpemUgPSAzLA0KICAgICAgICAgICAgY2hlY2tfb3ZlcmxhcCA9IFRSVUUpICsNCiAgdGhlbWVfdHVmdGUoKSArDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3M9c2VxKDE4OTYsIDIwMTYsIDEwKSkgKw0KICBsYWJzKHg9IiIsIHk9Ik51bWJlciBvZiBNZWRhbHMgV29uIiwgdGl0bGUgPSAiVG90YWwgTWVkYWxzIFdvbiBieSBZZWFyIikgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIA0KICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChjb2xvcj0iZ3JheTI5Iiwgc2l6ZT0xMCksIA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTUsIGZhY2U9Iml0YWxpYyIsIGhqdXN0PS0wLjEpKQ0KDQpsaW5lXzINCmBgYA0KDQpJIGRlcGVuZGluZyBvbiB3aGF0IHRoZSBlZGl0b3IgaXMgaW50ZXJlc3RlZCBpbiBzaG93aW5nLCBJIHdvdWxkIHN1Z2dlc3QgdXNpbmcgdGhlIGxpbmUgZ3JhcGggb2YgdGhlIGN1bXVsYXRpdmUgbnVtYmVyIG9mIG1lZGFscyBlYXJuZWQgYmVjYXVzZSBpdCBjbGVhcmx5IHBvcnRyYXlzIGJvdGggdGhlIGxhcmdlIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgdG90YWwgbnVtYmVyIG9mIG9mIG1lZGFscyBlYXJuZWQgKGllIHRoZSB2YWx1ZXMgc2hvd24gZm9yIDIwMTYpIGFuZCBzaG93cyBob3cgdGhlIHJhcGlkIGluY3JlYXNlIGluIHRoZSBudW1iZXIgb2YgbWVkYWxzIGNvbGxlY3RlZCBieSB0aGUgVVNTUiwgZGVzcGl0ZSBoYXZpbmcgcGFydGljaXBhdGVkIGluIGZld2VyIGdhbWVzLiBXaGF0IGhhcHBlbmVkIGR1cmluZyB0aGlzIHBlcmlvZCB0aGF0IGdhdmUgdGhlIFVTU1IgdGhlIGVkZ2U/DQoNCg0KIyMjIyAyLiBNZWRhbCBDb3VudHMgYWRqdXN0ZWQgYnkgUG9wdWxhdGlvbiwgR0RQDQoNCg0KRG9lcyBwb3B1bGF0aW9uIG9yIEdEUCBwZXIgY2FwaXRhIGhhdmUgYW55IGluZmx1ZW5jZSBvbiB3aW5uaW5nIHN1bW1lciBtZWRhbHM/DQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0KIyMgQ3JlYXRpbmcgYSBkYXRhc2V0IHNob3dpbmcgbWVkYWwgY291bnRzLCBwb3AsIGFuZCBnZHANCg0KbWVkYWxjb3VudCA8LSBhdGggJT4lDQogbXV0YXRlX2lmKGlzLm51bWVyaWMsIGZ1bnMoaWZlbHNlKGlzLm5hKC4pLCAwLCAuKSkpICU+JQ0KICBmaWx0ZXIoU2Vhc29uPT0iU3VtbWVyIikgJT4lDQogIGZpbHRlcihtZWRhbGZsYWc9PTEpICU+JQ0KICBncm91cF9ieShOT0MpICU+JQ0KICBzdW1tYXJpemUodG90YWwgPSBzdW0obWVkYWxmbGFnKSkgJT4lDQogIGFycmFuZ2UoZGVzYyh0b3RhbCkpICU+JQ0KICBtdXRhdGUocmFuaz1yb3dfbnVtYmVyKCkpICU+JQ0KICBmaWx0ZXIocmFuazwxMSkNCg0KIyMgRm9yIHNvbWUgcmVhc29uLCBTaW5nYXBvcmUgd2FzIG1pc2NvZGVkLiBJIGFsc28gaW5jbHVkZWQgUnVzc2lhIGluIHBsYWNlIG9mIFVTU1INCg0KZ2RwJE5PQyA8LSBhcy5jaGFyYWN0ZXIoZ2RwJENvZGUpDQpnZHAkTk9DW2dkcCRDb2RlID09ICJTSU4iXSA8LSAiU0dQIg0KZ2RwJE5PQ1tnZHAkQ29kZSA9PSAiUlVTIl0gPC0gIlVSUyINCm1lZGFsZ2RwIDwtIGxlZnRfam9pbihtZWRhbGNvdW50LCBnZHAsIGJ5PSJOT0MiKQ0KDQojIyBDcmVhdGVkIHZhcmlhYmxlcyBzaG93aW5nIHRoZSByYXRpbyBvZiBtZWRhbHMgd29uIHRvIHBvcCBhbmQgZ2RwDQoNCm1lZGFsZ2RwJHRvdGFscG9wIDwtIG1lZGFsZ2RwJHRvdGFsL21lZGFsZ2RwJFBvcHVsYXRpb24NCm1lZGFsZ2RwJHRvdGFsZ2RwIDwtIG1lZGFsZ2RwJHRvdGFsL21lZGFsZ2RwJEdEUC5wZXIuQ2FwaXRhDQpgYGANCg0KVGhlIGFib3ZlIHZpc3VhbGl6YXRpb25zIHNob3cgdGhlIHVuYWRqdXN0ZWQgbWVkYWwgcmFua2luZ3Mgb2YgZWFjaCBOT0MgLSBoZXJlLCBJIGNhbGN1bGF0ZWQgdGhlIHJhdGlvIG9mIG1lZGFscyB3b24gdG8gYm90aCBwb3B1bGF0aW9uIGFuZCBHRFAgcGVyIGNhcGl0YSBmb3IgZWFjaCBOT0MuIFRoZW4gSSBjcmVhdGVkIHR3byBuZXcgcmFua2luZ3MgZm9yIG1lZGFscyB3b24gdXNpbmcgdGhlc2UgcmF0aW9zLg0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCiMjIENyZWF0aW5nIHJhbmtpbmdzIGZvciBwb3B1bGF0aW9uDQoNCmZpbmFscG9wIDwtIG1lZGFsZ2RwICU+JQ0KICBtdXRhdGVfaWYoaXMubnVtZXJpYywgZnVucyhpZmVsc2UoaXMubmEoLiksIDAsIC4pKSkgJT4lDQogIGdyb3VwX2J5KE5PQywgdG90YWxwb3ApICU+JQ0KICBzdW1tYXJpemUoKSAlPiUNCiAgYXJyYW5nZShkZXNjKHRvdGFscG9wKSkNCg0KIyMgRm9yIHNvbWUgcmVhc29uIHRoZSByb3cgbnVtYmVyIGZ1bmN0aW9uIGRvZXNuJ3Qgd29yaywgc28gSSBoYXJkIGNvZGVkIHRoZSByYW5raW5ncw0KDQpmaW5hbHBvcCRyYW5rW2ZpbmFscG9wJE5PQz09IkhVTiJdIDwtIDENCmZpbmFscG9wJHJhbmtbZmluYWxwb3AkTk9DPT0iU1dFIl0gPC0gMg0KZmluYWxwb3AkcmFua1tmaW5hbHBvcCROT0M9PSJBVVMiXSA8LSAzDQpmaW5hbHBvcCRyYW5rW2ZpbmFscG9wJE5PQz09Ik5FRCJdIDwtIDQNCmZpbmFscG9wJHJhbmtbZmluYWxwb3AkTk9DPT0iR0JSIl0gPC0gNQ0KZmluYWxwb3AkcmFua1tmaW5hbHBvcCROT0M9PSJGUkEiXSA8LSA2DQpmaW5hbHBvcCRyYW5rW2ZpbmFscG9wJE5PQz09IklUQSJdIDwtIDcNCmZpbmFscG9wJHJhbmtbZmluYWxwb3AkTk9DPT0iR0VSIl0gPC0gOA0KZmluYWxwb3AkcmFua1tmaW5hbHBvcCROT0M9PSJVU0EiXSA8LSA5DQpmaW5hbHBvcCRyYW5rW2ZpbmFscG9wJE5PQz09IlVSUyJdIDwtIDEwDQoNCmZpbmFscG9wJHJhbmt0eXBlIDwtICJQb3AiDQpgYGANCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQojIyBDcmVhdGluZyByYW5raW5ncyBmb3IgR0RQDQoNCmZpbmFsZ2RwIDwtIG1lZGFsZ2RwICU+JQ0KICBtdXRhdGVfaWYoaXMubnVtZXJpYywgZnVucyhpZmVsc2UoaXMubmEoLiksIDAsIC4pKSkgJT4lDQogIGdyb3VwX2J5KE5PQywgdG90YWxnZHApICU+JQ0KICBzdW1tYXJpemUoKSAlPiUNCiAgYXJyYW5nZShkZXNjKHRvdGFsZ2RwKSkNCg0KIyMgRm9yIHNvbWUgcmVhc29uIHRoZSByb3cgbnVtYmVyIGZ1bmN0aW9uIGRvZXNuJ3Qgd29yaywgc28gSSBoYXJkIGNvZGVkIHRoZSByYW5raW5ncw0KDQpmaW5hbGdkcCRyYW5rW2ZpbmFsZ2RwJE5PQz09IlVSUyJdIDwtIDENCmZpbmFsZ2RwJHJhbmtbZmluYWxnZHAkTk9DPT0iSFVOIl0gPC0gMg0KZmluYWxnZHAkcmFua1tmaW5hbGdkcCROT0M9PSJVU0EiXSA8LSAzDQpmaW5hbGdkcCRyYW5rW2ZpbmFsZ2RwJE5PQz09IklUQSJdIDwtIDQNCmZpbmFsZ2RwJHJhbmtbZmluYWxnZHAkTk9DPT0iR0JSIl0gPC0gNQ0KZmluYWxnZHAkcmFua1tmaW5hbGdkcCROT0M9PSJGUkEiXSA8LSA2DQpmaW5hbGdkcCRyYW5rW2ZpbmFsZ2RwJE5PQz09IkdFUiJdIDwtIDcNCmZpbmFsZ2RwJHJhbmtbZmluYWxnZHAkTk9DPT0iQVVTIl0gPC0gOA0KZmluYWxnZHAkcmFua1tmaW5hbGdkcCROT0M9PSJTV0UiXSA8LSA5DQpmaW5hbGdkcCRyYW5rW2ZpbmFsZ2RwJE5PQz09Ik5FRCJdIDwtIDEwDQoNCmZpbmFsZ2RwJHJhbmt0eXBlIDwtICJHRFAiDQoNCmBgYA0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCiMjIENvbWJpbmluZyBhbGwgcmFua2luZ3MgaW50byBvbmUgZGF0YXNldA0KDQp0b3AxMG1lZGFsJHJhbmt0eXBlIDwtICJUb3RhbCINCg0KdG9wMTBtZWRhbC50ZW1wIDwtIHdpdGhpbih0b3AxMG1lZGFsLCBybSh0b3RhbG1lZGFsLCBDb3VudHJ5KSkNCmZpbmFsZ2RwIDwtIHdpdGhpbihmaW5hbGdkcCwgcm0odG90YWxnZHApKQ0KZmluYWxwb3AgPC0gd2l0aGluKGZpbmFscG9wLCBybSh0b3RhbHBvcCkpDQp0b3AxMG1lZGFsLnRlbXAkTk9DIDwtIGFzLmNoYXJhY3Rlcih0b3AxMG1lZGFsLnRlbXAkTk9DKQ0KDQoNCmNvbWJvbWVkYWwxIDwtIGJpbmRfcm93cyh0b3AxMG1lZGFsLnRlbXAsIGZpbmFsZ2RwLCBmaW5hbHBvcCkNCmBgYA0KDQpUaGUgZ3JhcGggYmVsb3cgc2hvd3MgdGhlIG5ldyBhZGp1c3RlZCByYW5raW5ncyBieSBOT0MsIGhpZ2hsaWdodGluZyBob3cgdGhlIFVTJ3MgcmFua2luZyBjaGFuZ2VzIHdoZW4gYWRqdXN0ZWQgYnkgR0RQIGFuZCBwb3B1bGF0aW9uOg0KDQpgYGB7cn0NCm11bHRpcGxlc18xIDwtIGdncGxvdChjb21ib21lZGFsMSwgYWVzKE5PQywgcmFuaywgZ3JvdXA9Tk9DKSkgKw0KICBnZW9tX2JhcihhZXMoZmlsbD1OT0MsIGFscGhhPTEpLCBzdGF0ID0gImlkZW50aXR5Iiwgd2lkdGggPSAwLjcsIHBvc2l0aW9uID0gImRvZGdlIikgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiZ3JleSIsICJncmV5IiwgImdyZXkiLCAiZ3JleSIsICJncmV5IiwgImdyZXkiLCAiZ3JleSIsICJncmV5IiwgImdyZXkiLCAidHVycXVvaXNlNCIpKSArDQogIHRoZW1lX3R1ZnRlKCkgKw0KICBjb29yZF9mbGlwKCkgKw0KICBsYWJzKHg9IiIsIHk9IlJhbmsiLCB0aXRsZSA9ICJNZWRhbHMgUmFua2luZ3MsIEFkanVzdGVkIGZvciBQb3B1bGF0aW9uIGFuZCBHRFAgcGVyIGNhcGl0YSIpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1zZXEoMCwgMTAsIDIpKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgDQogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGNvbG9yPSJncmF5MzAiLCBzaXplPTgpLA0KICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChjb2xvcj0iZ3JheTMwIiwgc2l6ZT0xMCksIA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTUsIGZhY2U9Iml0YWxpYyIpLA0KICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiZ3JleTk1IiwgY29sb3IgPSAid2hpdGUiKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShjb2xvcj0id2hpdGUiKSkgKw0KICBmYWNldF9ncmlkKHJvd3MgPSB2YXJzKHJhbmt0eXBlKSwgc2NhbGVzID0gImZyZWUiKQ0KDQptdWx0aXBsZXNfMQ0KYGBgDQoNCkZyb20gdGhlIGdyYXBoIHdlIGNhbiBzZWUgdGhhdCB3aGlsZSB0aGUgVVMgcmFua3MgMXN0IGluIG92ZXJhbGwgKHVuYWRqdXN0ZWQpIG1lZGFsIGNvdW50LCBpdCByYW5rcyBtdWNoIGxvd2VyIChhcm91bmQgOXRoIG91dCBvZiAxMCkgd2hlbiBhZGp1c3RlZCBmb3IgcG9wdWxhdGlvbi4gSXQgYWxzbyByYW5rcyBzbGlnaGx5IGxvd2VyIChhcm91bmQgM3JkIG91dCBvZiAxMCkgd2hlbiBhZGp1c3RlZCBmb3IgR0RQIHBlciBjYXBpdGEuIFRoaXMgY291bGQgc3VnZ2VzdCB0aGF0IHdoaWxlIGEgY291bnRyeSdzIHBvcHVsYXRpb24gbWlnaHQgbm90IGZhY3RvciBpbnRvIGEgY291bnRyeSdzIHN1bW1lciBtZWRhbCB3aW5uaW5ncywgR0RQIHBlciBjYXBpdGEgbWlnaHQuDQoNCg0KIyMjIyAzLiBIb3N0IENvdW50cnkgQWR2YW50YWdlDQoNCg0KVGhlc2UgbmV4dCB2aXN1YWxpemF0aW9ucyBhdHRlbXB0IHRvIGludmVzdGlnYXRlIHdoZXRoZXIgdGhlIHRvcCAxMCBzdW1tZXIgT2x5bXBpY3MgbWVkYWwgd2lubmVycyBvZiBhbGwgdGltZSBzaG93ZWQgYW55IGhvc3QgY291bnRyeSBhZHZhbnRhZ2UuDQoNCmBgYHtyfQ0KIyMgVGhpcyBpcyB0aGUgY29kZSBJIGNvcGllZCBmcm9tIHRoZSBBc3NpZ25tZW50IEluc3RydWN0aW9ucyB3aGljaCBicmluZ3MgaW4gdGhlIGhvc3QgY291bnRyeSBkYXRhc2V0LiBJIGFkZGVkIGEgc3BhY2UgYWZ0ZXIgdGhlICIsIiB0byBtYWtlIG1hdGNoaW5nIHRoZSBjb3VudHJpZXMgZWFzaWVyIChzZWUgYmVsb3cpDQoNCndpa2lfaG9zdHMgPC0gcmVhZF9odG1sKCJodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9TdW1tZXJfT2x5bXBpY19HYW1lcyIpDQpob3N0cyA8LSBodG1sX3RhYmxlKGh0bWxfbm9kZXMod2lraV9ob3N0cywgInRhYmxlIilbWzhdXSwgZmlsbD1UUlVFKQ0KaG9zdHMgPC0gaG9zdHNbLTEsMTozXQ0KaG9zdHMkY2l0eSA8LSBzdHJfc3BsaXRfZml4ZWQoaG9zdHMkSG9zdCwgbj0yLCAiLCAiKVssMV0NCmhvc3RzJGNvdW50cnkgPC0gc3RyX3NwbGl0X2ZpeGVkKGhvc3RzJEhvc3QsIG49MiwgIiwgIilbLDJdDQpgYGANCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQojIyBDcmVhdGluZyBhIG5ldyBkYXRhc2V0IGxpa2UgdGhlIG9uZXMgYWJvdmUNCg0KaG9zdCA8LSBhdGggJT4lDQogIG11dGF0ZV9pZihpcy5udW1lcmljLCBmdW5zKGlmZWxzZShpcy5uYSguKSwgMCwgLikpKSAlPiUNCiAgZmlsdGVyKFNlYXNvbj09IlN1bW1lciIpICU+JQ0KICBncm91cF9ieShOT0MpICU+JQ0KICBtdXRhdGUodG90YWxtZWRhbCA9IHN1bShtZWRhbGZsYWcpKSAlPiUNCiAgdW5ncm91cCgpICU+JQ0KICBmaWx0ZXIoTk9DICVpbiUgdG9wMTBtZWRhbCROT0MpICU+JQ0KICBhcnJhbmdlKGRlc2ModG90YWxtZWRhbCkpDQoNCiMjIEpvaW5pbmcgdGhlIGFib3ZlIGRhdGFzZXQgd2l0aCB0aGUgaG9zdCBjb3VudHJ5IGRhdGFzZXQgYnkgeWVhcg0KDQpob3N0cyRZZWFyIDwtIGFzLmludGVnZXIoaG9zdHMkWWVhcikNCmNvbWJvaG9zdHMgPC0gbGVmdF9qb2luKGhvc3QsIGhvc3RzLCBieSA9ICJZZWFyIikNCmBgYA0KDQpBdCB0aGlzIHBvaW50IEkgYWxzbyBsZWFybmVkIHRoYXQgdGhlcmUgd2FzIGFjdHVhbGx5IG5vIG9mZmljaWFsIDE5MDYgU3VtbWVyIE9seW1waWNzIChkZXNwaXRlIHRoZSBpbmNsdXNpb24gb2YgYSAxOTA2IE9seW1waWNzIGluIEF0aGVucyBpbiB0aGUgZGF0YXNldCkuIEhvd2V2ZXIgSSBkZWNpZGVkIHRvIGluY2x1ZGUgdGhlIDE5MDYgZGF0YSBzaW5jZSBJIGhhZCBhbHNvIGluY2x1ZGVkIGl0IGluIHRoZSBncmFwaHMgYWJvdmUuDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0KIyMgSGVyZSBJJ20ganVzdCBjcmVhdGluZyBhIHZhcmlhYmxlIHRoYXQgcmVuYW1lcyBlYWNoIGNvdW50cnkgdGhhdCBoYXMgaG9zdGVkIGEgc3VtbWVyIG9seW1waWNzIHdpdGggdGhhdCBjb3VudHJ5J3MgTk9DLiBJIGRpZCB0aGlzIHRvIG1ha2UgaXQgZWFzaWVyIHRvIG1hdGNoIHRlYW1zIHdpdGggdGhlIGhvc3RpbmcgY291bnRyeS4NCg0KY29tYm9ob3N0cyRjb3VudHJ5W2NvbWJvaG9zdHMkQ2l0eT09IkF0aGluYSJdIDwtICJHcmVlY2UiDQoNCmNvbWJvaG9zdHMkaG9zdE5PQ1tjb21ib2hvc3RzJGNvdW50cnk9PSJVbml0ZWQgU3RhdGVzIl0gPC0gIlVTQSINCmNvbWJvaG9zdHMkaG9zdE5PQ1tjb21ib2hvc3RzJGNvdW50cnk9PSJTb3ZpZXQgVW5pb24iXSA8LSAiVVJTIg0KY29tYm9ob3N0cyRob3N0Tk9DW2NvbWJvaG9zdHMkY291bnRyeT09IlN3ZWRlbiJdIDwtICJTV0UiDQpjb21ib2hvc3RzJGhvc3ROT0NbY29tYm9ob3N0cyRjb3VudHJ5PT0iTmV0aGVybGFuZHMiXSA8LSAiTkVEIg0KY29tYm9ob3N0cyRob3N0Tk9DW2NvbWJvaG9zdHMkY291bnRyeT09Ikl0YWx5Il0gPC0gIklUQSINCmNvbWJvaG9zdHMkaG9zdE5PQ1tjb21ib2hvc3RzJGNvdW50cnk9PSJIdW5nYXJ5Il0gPC0gIkhVTiINCmNvbWJvaG9zdHMkaG9zdE5PQ1tjb21ib2hvc3RzJGNvdW50cnk9PSJHZXJtYW55Il0gPC0gIkdFUiINCmNvbWJvaG9zdHMkaG9zdE5PQ1tjb21ib2hvc3RzJGNvdW50cnk9PSJVbml0ZWQgS2luZ2RvbSJdIDwtICJHQlIiDQpjb21ib2hvc3RzJGhvc3ROT0NbY29tYm9ob3N0cyRjb3VudHJ5PT0iR2VybWFueSJdIDwtICJHRVIiDQpjb21ib2hvc3RzJGhvc3ROT0NbY29tYm9ob3N0cyRjb3VudHJ5PT0iV2VzdCBHZXJtYW55Il0gPC0gIkdFUiINCmNvbWJvaG9zdHMkaG9zdE5PQ1tjb21ib2hvc3RzJGNvdW50cnk9PSJBdXN0cmFsaWEiXSA8LSAiQVVTIg0KDQpjb21ib2hvc3RzJGhvc3ROT0NbY29tYm9ob3N0cyRjb3VudHJ5PT0iQmVsZ2l1bSJdIDwtICJCRUwiDQpjb21ib2hvc3RzJGhvc3ROT0NbY29tYm9ob3N0cyRjb3VudHJ5PT0iQnJhemlsIl0gPC0gIkJSQSINCmNvbWJvaG9zdHMkaG9zdE5PQ1tjb21ib2hvc3RzJGNvdW50cnk9PSJDYW5hZGEiXSA8LSAiQ0FOIg0KY29tYm9ob3N0cyRob3N0Tk9DW2NvbWJvaG9zdHMkY291bnRyeT09IkNoaW5hIl0gPC0gIkNITiINCmNvbWJvaG9zdHMkaG9zdE5PQ1tjb21ib2hvc3RzJGNvdW50cnk9PSJGaW5sYW5kIl0gPC0gIkZJTiINCmNvbWJvaG9zdHMkaG9zdE5PQ1tjb21ib2hvc3RzJGNvdW50cnk9PSJGcmFuY2UiXSA8LSAiRlJBIg0KY29tYm9ob3N0cyRob3N0Tk9DW2NvbWJvaG9zdHMkY291bnRyeT09IkdyZWVjZSJdIDwtICJHUkUiDQpjb21ib2hvc3RzJGhvc3ROT0NbY29tYm9ob3N0cyRjb3VudHJ5PT0iU3BhaW4iXSA8LSAiRVNQIg0KY29tYm9ob3N0cyRob3N0Tk9DW2NvbWJvaG9zdHMkY291bnRyeT09IkphcGFuIl0gPC0gIkpQTiINCmNvbWJvaG9zdHMkaG9zdE5PQ1tjb21ib2hvc3RzJGNvdW50cnk9PSJNZXhpY28iXSA8LSAiTUVYIg0KY29tYm9ob3N0cyRob3N0Tk9DW2NvbWJvaG9zdHMkY291bnRyeT09IlNvdXRoIEtvcmVhIl0gPC0gIktPUiINCmBgYA0KDQpMb29raW5nIGF0IGEgdGFibGUgb2YgdGhlIGZpbmFsIGRhdGFzZXQgc2hvd3MgdGhhdCBhbW9uZyB0aGUgdG9wIDEwIG1lZGFsLWVhcm5pbmcgTk9DcywgYWxsIGJ1dCBIdW5ncnkgaGF2ZSBwYXJ0aWNpcGF0ZWQgaW4gc3VtbWVyIGdhbWVzIHRoZXkgaGF2ZSBob3N0ZWQuDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0KIyMgQ3JlYXRpbmcgYSBmbGFnIGZvciBlYWNoIGF0aGVsZXRlIGZvciB3aGV0aGVyIHRoZXkgd2VyZSBwbGF5aW5nIGluIHRoZWlyIHRlYW0ncyBjb3VudHJ5Lg0KDQpjb21ib2hvc3RzJGhvc3RfZmxhZyA8LSBpZmVsc2UoY29tYm9ob3N0cyROT0M9PWNvbWJvaG9zdHMkaG9zdE5PQywgMSwgMCkNCg0KIyMgQ3JlYXRpbmcgdGhlIGZpbmFsIGRhdGFzZXQgd2l0aCB0aGUgYXZlcmFnZSBudW1iZXIgb2YgbWVkYWxzIGVhcm5lZCBwZXIgc3VtbWVyIGdhbWUgZm9yIGhvc3RlZCBnYW1lcyBhbmQgbm90LWhvc3RlZCBnYW1lcw0KDQpob3N0X3RvdGFsIDwtIGNvbWJvaG9zdHMgJT4lDQogIGdyb3VwX2J5KE5PQywgaG9zdF9mbGFnKSAlPiUNCiAgbXV0YXRlKGNvdW50Z2FtZXMgPSBuX2Rpc3RpbmN0KFllYXIpKSAlPiUNCiAgdW5ncm91cCgpICU+JQ0KICBncm91cF9ieShOT0MsIGhvc3RfZmxhZykgJT4lDQogIG11dGF0ZShob3N0dG90YWwgPSBzdW0obWVkYWxmbGFnKSkgJT4lDQogIHVuZ3JvdXAoKSAlPiUNCiAgbXV0YXRlKG1lZGFsYXZlID0gaG9zdHRvdGFsL2NvdW50Z2FtZXMpICU+JQ0KICBncm91cF9ieShOT0MsIGhvc3RfZmxhZywgY291bnRnYW1lcywgdG90YWxtZWRhbCwgaG9zdHRvdGFsLCBtZWRhbGF2ZSkgJT4lDQogIHN1bW1hcmlzZSgpICU+JQ0KICBhcnJhbmdlKE5PQywgaG9zdF9mbGFnKSAlPiUNCiAgdW5ncm91cCgpDQoNCmhvc3RfdG90YWwkaG9zdF9mbGFnIDwtIGlmZWxzZShob3N0X3RvdGFsJGhvc3RfZmxhZz09MSwgIkhvc3RlZCIsICJOb3QgSG9zdGVkIikNCmhvc3RfdG90YWwNCmBgYA0KDQpGaW5hbGx5LCBJIGNyZWF0ZWQgYSBzbG9wZ3JhcGggc2hvd2luZyB0aGUgYXZlcmFnZSBudW1iZXIgb2YgbWVkYWxzIHdvbiBwZXIgZ2FtZXMgZm9yIGVhY2ggTk9DIGZvciB3aGVuIHRoZXkgd2VyZSBub3QgaG9zdGluZywgYW5kIHdoZW4gdGhleSB3ZXJlIGhvc3Rpbmc6DQoNCmBgYHtyfQ0Kc2xvcGVncmFwaF8xIDwtIGdncGxvdChob3N0X3RvdGFsLCBhZXMoaG9zdF9mbGFnLCBtZWRhbGF2ZSwgZ3JvdXA9Tk9DKSkgKw0KICBnZW9tX2xpbmUoYWVzKGNvbG9yID0gaWZlbHNlKGhvc3RfdG90YWwkTk9DPT0iVVNBIiwgIlVTQSIsICIiKSwgYWxwaGE9MSksIHNpemUgPSAxLjUpICsNCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBpZmVsc2UoaG9zdF90b3RhbCROT0M9PSJVU0EiLCAiVVNBIiwgIiIpLCBhbHBoYT0xKSwgc2l6ZSA9IDMpICsNCiAgZ2VvbV90ZXh0KGRhdGEgPSBob3N0X3RvdGFsICU+JSBmaWx0ZXIoaG9zdF9mbGFnPT0iSG9zdGVkIiksIA0KICAgICAgICAgICAgYWVzKGxhYmVsID0gcGFzdGUwKE5PQykpLCANCiAgICAgICAgICAgIGhqdXN0ID0gLS4zNSwNCiAgICAgICAgICAgIGNvbG9yID0gImdyYXkyOSIsDQogICAgICAgICAgICBzaXplID0gMywNCiAgICAgICAgICAgIGNoZWNrX292ZXJsYXAgPSBUUlVFKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiZ3JleSIsICJ0dXJxdW9pc2U0IikpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1zZXEoMCwgNTUwLCAxMDApKSArDQogIHNjYWxlX3hfZGlzY3JldGUobGltaXRzPWMoIk5vdCBIb3N0ZWQiLCAiSG9zdGVkIikpICsNCiAgdGhlbWVfdHVmdGUoKSArDQogIGxhYnMoeD0iIiwgeT0iIiwgdGl0bGUgPSAiQXZlcmFnZSBOdW1iZXIgb2YgTWVkYWxzIFdvbiwgcGVyIE9seW1waWMgR2FtZXMiKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgDQogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGNvbG9yPSJncmF5MjkiLCBzaXplPTEyKSwgDQogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGNvbG9yPSJncmF5MjkiLCBzaXplPTEyKSwgDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xNywgZmFjZT0iaXRhbGljIiwgaGp1c3Q9LjIsIHZqdXN0ID0gMSksIA0KICAgICAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2xpbmUoY29sb3IgPSAibGlnaHRncmV5IiksIA0KICAgICAgICBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpKQ0KDQpzbG9wZWdyYXBoXzENCmBgYA0KDQpMb29raW5nIGF0IHRoZSBzbG9wZWdyYXBoLCBpdCB3b3VsZCBhcHBlYXIgdGhhdCBvbiBhdmVyYWdlLCBOT0NzIGVhcm4gbW9yZSBtZWRhbHMgcGVyIE9seW1waWMgZ2FtZXMgd2hlbiB0aGV5IGFyZSBob3N0aW5nIHRoYW4gd2hlbiB0aGV5IGFyZSBub3QgaG9zdGluZy4gSWYgYSBwYXJ0aWN1bGFyIGNvdW50cnkgd2FudHMgdG8gaW5jcmVhc2UgdGhlaXIgbWVkYWwgY291bnQsIHRoZXkgbWlnaHQgd2FudCB0byBjb25zaWRlciBob3N0aW5nIHRoZSBzdW1tZXIgZ2FtZXMhDQoNCg0KIyMjIyA0LiBNb3N0IHN1Y2Nlc3NmdWwgYXRobGV0ZXMNCg0KVGhlIG5leHQgc2V0IG9mIHZpc3VhbGl6YXRpb25zIGxvb2sgYXQgdGhlIG1vc3QgInN1Y2Nlc3NmdWwiIGF0aGxldGVzIGFtb25nIHRoZSB0b3AgMTAgbWVkYWwtd2lubmluZyBOT0NzIGZvciB0aGUgU3VtbWVyIE9seW1waWNzLiBJbiBwYXJ0aWN1bGFyLCB3ZSdyZSBpbnRlcmVzdGVkIGluIHNlZWluZyB3aGljaCBhdGhsZXRlcyBhbmQgc3BvcnQgZWFybiB0aGUgbW9zdCBtZWRhbHMuDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0KIyMgQ3JlYXRpbmcgbmV3IGRhdGFzZXQgbGlzdGluZyAxMCBtb3N0IHN1Y2Nlc2Z1bCBhdGhsZXRlcyBvZiBhbGwgdGltZQ0KDQp0b3AxMHN1Y2VzcyA8LSBhdGggJT4lDQogIG11dGF0ZV9pZihpcy5udW1lcmljLCBmdW5zKGlmZWxzZShpcy5uYSguKSwgMCwgLikpKSAlPiUNCiAgZmlsdGVyKFNlYXNvbj09IlN1bW1lciIpICU+JQ0KICBncm91cF9ieShJRCkgJT4lDQogIG11dGF0ZSh0b3RhbG1lZGFsID0gc3VtKG1lZGFsZmxhZykpICU+JQ0KICB1bmdyb3VwKCkgJT4lDQogIGZpbHRlcihOT0MgJWluJSB0b3AxMG1lZGFsJE5PQykgJT4lDQogIGFycmFuZ2UoZGVzYyh0b3RhbG1lZGFsKSkgJT4lDQogIGdyb3VwX2J5KElELCBOYW1lLCBTZXgsIHRvdGFsbWVkYWwsIE5PQywgU3BvcnQpICU+JQ0KICBzdW1tYXJpemUoKSAlPiUNCiAgdW5ncm91cCAlPiUNCiAgYXJyYW5nZShkZXNjKHRvdGFsbWVkYWwpKSAlPiUNCiAgbXV0YXRlKHJhbms9cm93X251bWJlcigpKSAlPiUNCiAgZmlsdGVyKHJhbms8MTEpICU+JQ0KICB1bmdyb3VwKCkNCg0KdG9wMTBzdWNlc3MkU2V4IDwtIGlmZWxzZSh0b3AxMHN1Y2VzcyRTZXg9PSJGIiwgIkZlbWFsZSIsICJNYWxlIikNCmBgYA0KDQpGaXJzdCwgdGhlIGJlbG93IGdyYXBoIHNob3dzIHRoZSB0b3AgMTAgYmlnZ2VzdCBtZWRhbC13aW5uZXJzIG9mIGFsbCB0aW1lIGZvciB0aGUgU3VtbWVyIGdhbWVzIG9ubHk6DQoNCmBgYHtyfQ0KIyMgQ3JlYXRpbmcgYSBkb3RwbG90IHNlcGVyYXRlZCBieSBOT0MNCg0KZG90cGxvdF8xIDwtIGdncGxvdCh0b3AxMHN1Y2VzcywgYWVzKHRvdGFsbWVkYWwsIHJlb3JkZXIoTmFtZSwgdG90YWxtZWRhbCksIGdyb3VwPU5PQykpICsNCiAgZ2VvbV9wb2ludChhZXMoY29sb3I9Tk9DLCBhbHBoYT0xKSwgc2l6ZT01KSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiZ3JleSIsICJncmV5IiwgImdyZXkiLCAidHVycXVvaXNlNCIpKSArDQogIHRoZW1lX3R1ZnRlKCkgKw0KICBsYWJzKHg9IlRvdGFsIE1lZGFscyBXb24iLCB5PSIiLCB0aXRsZSA9ICJUb3AgMTAgQmlnZ2VzdCBNZWRhbCBXaW5uZXJzIChTdW1tZXIgR2FtZXMgT25seSkiKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgDQogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGNvbG9yPSJncmF5MzAiLCBzaXplPTEwKSwNCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoY29sb3I9ImdyYXkzMCIsIHNpemU9MTApLCANCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTE1LCBmYWNlPSJpdGFsaWMiLCBoanVzdD0xLjUpLA0KICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiZ3JleTk1IiwgY29sb3IgPSAid2hpdGUiKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShjb2xvcj0id2hpdGUiKSkgKw0KICBmYWNldF9ncmlkKHJvd3MgPSB2YXJzKE5PQyksIHNjYWxlcyA9ICJmcmVlIiwgc3BhY2UgPSAiZnJlZSIpDQoNCmRvdHBsb3RfMQ0KYGBgDQoNCkZyb20gdGhlIGRvdHBsb3QgYWJvdmUsIHdlIGNhbiBzZWUgdGhhdCBtb3N0IG9mIHRoZSB0b3AgMTAgaGlnaGVzdCBhY2hpZXZpbmcgYXRobGV0ZXMgYXJlIG9uIHRoZSBVUyB0ZWFtLiBBZGRpdGlvbmFsbHksTWljaGFlbCBQaGVscHMgaGFzIHRoZSBtb3N0IHRvdGFsIG1lZGFscyBvZiBhbGwgdGltZS4NCg0KTmV4dCwgSSBsb29rZWQgYXQgdGhlIGRpc3RyaWJ1dGlvbiBvZiBtZWRhbHMgd29uIGFjcm9zcyBzcG9ydCBhbmQgZ2VuZGVyOg0KDQpgYGB7cn0NCiMjIFBsb3R0aW5nIE1lZGFscyBXb24gYnkgU3BvcnQgYW5kIEdlbmRlcg0KDQpiYXJfMyA8LSBnZ3Bsb3QodG9wMTBzdWNlc3MsIGFlcyhyZW9yZGVyKFNleCwgdG90YWxtZWRhbCksIHRvdGFsbWVkYWwsIGdyb3VwPVNleCkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMC43LCBmaWxsPSJ0dXJxdW9pc2U0IikgKw0KICB0aGVtZV90dWZ0ZSgpICsNCiAgbGFicyh4PSJHZW5kZXIiLCB5PSJUb3RhbCBNZWRhbHMgV29uIiwgdGl0bGUgPSAiTWVkYWxzIFdvbiBieSBTcG9ydCBhbmQgR2VuZGVyIikgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIA0KICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChjb2xvcj0iZ3JheTMwIiwgc2l6ZT0xMCksDQogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGNvbG9yPSJncmF5MzAiLCBzaXplPTEwKSwgDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xNSwgZmFjZT0iaXRhbGljIiksDQogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJncmV5OTUiLCBjb2xvciA9ICJ3aGl0ZSIpLA0KICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGNvbG9yPSJ3aGl0ZSIpKSArDQogIGZhY2V0X2dyaWQoY29scyA9IHZhcnMoU3BvcnQpLCBzY2FsZXMgPSAiZnJlZSIsIHNwYWNlID0gImZyZWUiKQ0KDQpiYXJfMw0KYGBgDQoNCkZyb20gdGhlIGdyYXBoLCBpdCB3b3VsZCBhcHBlYXIgdGhhdCBvdXQgb2YgdGhlIHRvcCAxMCBiaWdnZXN0IG1lZGFsLXdpbm5pbmcgTk9DcyBkdXJpbmcgdGhlIFN1bW1lciBHYW1lcywgbWFsZSBzd2ltbWVycyB3ZXJlIHRoZSBtb3N0IHN1Y2Vzc2Z1bCBtZWRhbC13aW5uZXJzIChpZSwgd29uIHRoZSBtb3N0IG1lZGFscyBvdmVyYWxsKS4gRG9lcyB0aGlzIG1lYW4gdGhhdCBjb3VudHJpZXMgd2hvIHdhbnQgdG8gd2luIG1vcmUgU3VtbWVyIE9seW1waWMgbWVkYWxzIHNob3VsZCB0cmFpbiBtb3JlIHN3aW1tZXJzPw0KDQoNCiMjIyMgNS4gTWFrZSB0d28gcGxvdHMgaW50ZXJhY3RpdmUNCg0KDQpJIGNob3NlIHRvIG1ha2UgdGhlIGFib3ZlIGxpbmUgYW5kIHNsb3BlIGdyYXBocyBpbnRlcmFjdGl2ZSBiZWNhdXNlIEkgZmVsdCByZWFkZXJzIG1pZ2h0IGJlIGludGVyZXN0ZWQgaW4gaG92ZXJpbmcgb3ZlciBjZXJ0YWluIHBvaW50cyB0byBvYnRhaW4gdGhlaXIgYWN0dWFsIHZhbHVlcy4gQWx0aG91Z2ggdGhlIHN0YXRpYyB2ZXJzaW9uIG9mIGVhY2ggZ3JhcGggZG9lcyBnaXZlIGFuIG92ZXJhbGwgaW1wcmVzc2lvbiBvZiB0aGUgZGF0YSwgc29tZSByZWFkZXJzIG1heSBiZSBtb3JlIGludGVyZXN0ZWQgaW4gbGVhcm5pbmcgdGhlIHBhcnRpY3VsYXJzIG9mIGEgY2VydGFpbiB5ZWFyIG9yIGNvdW50cnkuIEFkZGl0aW9uYWxseSwgdGhlIGFiaWxpdHkgdG8gem9vbSBpbiBvbiBhbiBpbWFnZSBtYXkgbWFrZSB0aGUgbGluZSBncmFwaCBlYXNpZXIgdG8gaW50ZXJwcmV0IChwYXJ0aWN1bGFybHkgYXQgdGhlIGxvdy1lbmQgb2YgdGhlIHggYXhpcyB3aGVyZSBtYW55IG9mIHRoZSBsaW5lcyBvdmVybGFwKQ0KDQpgYGB7cn0NCmdsaW5lIDwtIGdncGxvdGx5KGxpbmVfMSkNCg0KZ2xpbmUNCmBgYA0KDQoNCmBgYHtyfQ0KZ3Nsb3BlIDwtIGdncGxvdGx5KHNsb3BlZ3JhcGhfMSkNCg0KZ3Nsb3BlDQpgYGANCg0KDQojIyMjIDYuIERhdGEgVGFibGUNCg0KDQpUaGUgZGF0YSB0YWJsZSBiZWxvdyBjb250YWlucyBkYXRhIGZvciBvbmx5IFN1bW1lciBHYW1lcywgYW5kIHNob3dzIHRoZSBudW1iZXIgb2YgbWVkYWxzIHdvbiBieSBzcG9ydCBmb3IgZWFjaCBOT0MgYW5kIHllYXIuIEkgY2hvc2UgdGhlc2UgdmFyaWFibGVzIGJlY2F1c2UgSSBmZWx0IHJlYWRlcnMgbWlnaHQgYmUgaW50ZXJlc3RlZCB0byBicm93c2UgdGhlIG51bWJlciBvZiBtZWRhbHMgd29uIGJ5IHNwb3J0IGZvciBBTEwgTk9Dcywgbm90IGp1c3QgbWVkYWxzIHdvbiBieSB0aGUgdG9wIDEwIG1lZGFsLXdpbm5lcnMgYWJvdmUuDQoNCmBgYHtyfQ0KIyMgUHJlcGFyaW5nIGEgZGF0ZWZyYW1lIGZvciB0aGUgdGFibGUgdGhhdCBpbmNsdWRlcyBtb3N0IHZhcmlhYmxlcyB1c2VkIGluIHRoZSBhYm92ZSB2aXN1YWxpemF0aW9ucw0KDQpuZXdkYXRhIDwtIGF0aCAlPiUNCiAgbXV0YXRlX2lmKGlzLm51bWVyaWMsIGZ1bnMoaWZlbHNlKGlzLm5hKC4pLCAwLCAuKSkpICU+JQ0KICBmaWx0ZXIoU2Vhc29uPT0iU3VtbWVyIikgJT4lDQogIGZpbHRlcihtZWRhbGZsYWc9PTEpICU+JQ0KICBncm91cF9ieShOT0MsIFllYXIsIFNwb3J0KSAlPiUNCiAgc3VtbWFyaXplKE1lZGFscyA9IHN1bShtZWRhbGZsYWcpKQ0KDQpuZXdkYXRhICU+JQ0KICBkYXRhdGFibGUoDQogICAgcm93bmFtZXMgPSBGQUxTRSwNCiAgICBmaWx0ZXIgPSBsaXN0KHBvc2l0aW9uID0gInRvcCIpLA0KICAgIG9wdGlvbnMgPSBsaXN0KGxhbmd1YWdlID0gbGlzdChzU2VhcmNoID0gIkZpbHRlcjoiKSkpDQpgYGANCg==